package ludichat.cobbreeding

import cn.hutool.json.JSONUtil
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.abilities.Ability
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.pokemon.HatchEggEvent
import com.cobblemon.mod.common.api.pokemon.Natures
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeature
import com.cobblemon.mod.common.api.pokemon.feature.StringSpeciesFeature
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.pokemon.Gender
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.util.asTranslated
import com.google.gson.Gson
import com.google.gson.JsonObject
import com.mojang.logging.LogUtils.getLogger
import kotlinx.serialization.json.Json
import ludichat.cobbreeding.components.CobbreedingComponents
import net.minecraft.core.component.DataComponentType
import net.minecraft.network.chat.Component
import net.minecraft.ChatFormatting
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag
import net.minecraft.world.level.Level
import org.slf4j.Logger
import kotlin.math.floor
import kotlin.math.log

/**
 * Pokémon egg item.
 */
class PokemonEgg(settings: Properties) : Item(settings) {
    companion object {
        const val DEFAULT_TIMER = 600
        const val DEFAULT_SECOND = 0

        val TIMER: DataComponentType<Int> by lazy { CobbreedingComponents.TIMER.get() }
        val SECOND: DataComponentType<Int> by lazy { CobbreedingComponents.SECOND.get() }
        val EGG_INFO: DataComponentType<String> by lazy { CobbreedingComponents.EGG_INFO.get() }
        val POKEMON_PROPERTIES: DataComponentType<PokemonProperties> by lazy { CobbreedingComponents.POKEMON_PROPERTIES.get() }
    }

    override fun verifyComponentsAfterLoad(itemStack: ItemStack) {
        super.verifyComponentsAfterLoad(itemStack)

        // Filter out items that already use components
        if (itemStack.has(POKEMON_PROPERTIES)) {
            itemStack.set(EGG_INFO, itemStack.get(POKEMON_PROPERTIES)!!.asString(" "))
        }
    }

    @JvmField
    val LOGGER: Logger = getLogger()
    override fun appendHoverText(
        stack: ItemStack,
        context: TooltipContext,
        lines: MutableList<Component>,
        type: TooltipFlag
    ) {
        super.appendHoverText(stack, context, lines, type)

        val properties = stack.get(EGG_INFO)?.let { PokemonProperties.parse(it) }

        if (properties?.species != null) {
            val pokemon = PokemonSpecies.getByName(properties.species!!)
            if (pokemon != null) {
                lines.add(pokemon.translatedName)

                if (properties.form != null) {
                    val data = pokemon.forms.find { it.formOnlyShowdownId() == properties.form }
                    if (data is FormData && data.name != "Normal") lines.add(Component.literal(data.name))
                }
            }

            // 显示闪光状态
            if (properties.shiny == true) {
                lines.add(Component.literal("✨ Shiny").withStyle(ChatFormatting.GOLD))
            }

            // 显示性别
            if (properties.gender != null) {
                val genderName = when (properties.gender) {
                    Gender.MALE -> "♂"
                    Gender.FEMALE -> "♀"
                    Gender.GENDERLESS -> "无性别"
                    else -> "未知"
                }
                val genderColor = when (properties.gender) {
                    Gender.MALE -> ChatFormatting.BLUE
                    Gender.FEMALE -> ChatFormatting.LIGHT_PURPLE
                    else -> ChatFormatting.GRAY
                }
                lines.add(Component.literal("${properties.gender}: $genderName").withStyle(genderColor))
            }

            // 显示性格
            if (properties.nature != null) {
                var natureName = properties.nature
                //如果natureName不为空,取的冒号后面那位
                if (natureName!!.contains(":")) {
                    natureName = natureName.split(":")[1].trim()
                    natureName = Natures.getNature(natureName)!!.displayName.asTranslated().string
                }





                lines.add(Component.literal("性格: $natureName").withStyle(ChatFormatting.YELLOW))
            }

            // 显示特性
            if (properties.ability != null) {
                var abilityName = properties.ability
                if (abilityName!!.isNotEmpty()) {
                    abilityName = ("cobblemon.ability.$abilityName").asTranslated().string
                }
                lines.add(Component.literal("特性: $abilityName").withStyle(ChatFormatting.GREEN))
            }

            // 显示IV数值
            if (properties.ivs != null) {
                val ivs = properties.ivs!!
                val hp = ivs[Stats.HP] ?: 0
                val atk = ivs[Stats.ATTACK] ?: 0
                val def = ivs[Stats.DEFENCE] ?: 0
                val spatk = ivs[Stats.SPECIAL_ATTACK] ?: 0
                val spdef = ivs[Stats.SPECIAL_DEFENCE] ?: 0
                val speed = ivs[Stats.SPEED] ?: 0

                // 计算31IV的数量
                val perfectIVs = listOf(hp, atk, def, spatk, spdef, speed).count { it == 31 }

                // 显示6V的特殊标记，5V和4V的标记

                if (perfectIVs >= 6) {
                    lines.add(Component.literal("⭐ 6V Perfect!").withStyle(ChatFormatting.GOLD))
                }else if (perfectIVs == 5) {
                    lines.add(Component.literal("💎 5V Great!").withStyle(ChatFormatting.AQUA))
                } else if (perfectIVs == 4) {
                    lines.add(Component.literal("❤ 4V Good!").withStyle(ChatFormatting.RED))
                }

                // 显示详细IV数值
                lines.add(Component.literal("IVs:").withStyle(ChatFormatting.GRAY))
                lines.add(Component.literal("${Stats.HP.displayName.string}: $hp  ${Stats.ATTACK.displayName.string}: $atk   ${Stats.DEFENCE.displayName.string}: $def").withStyle(ChatFormatting.WHITE))
                lines.add(Component.literal("${Stats.SPECIAL_ATTACK.displayName.string}: $spatk  ${Stats.SPECIAL_DEFENCE.displayName.string}: $spdef  ${Stats.SPEED.displayName.string}: $speed").withStyle(ChatFormatting.WHITE))
            }

            // 显示种族值
            if (pokemon != null) {
                val form = if (properties.form != null) {
                    LOGGER.warn("form: ${properties.form}")
                    pokemon.getFormByShowdownId(properties.form!!)
                } else {
                    pokemon.standardForm
                }

                val baseStats = form.baseStats
                val hpBase = baseStats[Stats.HP] ?: 0
                val atkBase = baseStats[Stats.ATTACK] ?: 0
                val defBase = baseStats[Stats.DEFENCE] ?: 0
                val spatkBase = baseStats[Stats.SPECIAL_ATTACK] ?: 0
                val spdefBase = baseStats[Stats.SPECIAL_DEFENCE] ?: 0
                val speedBase = baseStats[Stats.SPEED] ?: 0

                // 计算种族值总和
                val totalBase = hpBase + atkBase + defBase + spatkBase + spdefBase + speedBase

                lines.add(Component.literal("种族值: (总计: $totalBase)").withStyle(ChatFormatting.DARK_PURPLE))
                lines.add(Component.literal("${Stats.HP.displayName.string}: $hpBase  ${Stats.ATTACK.displayName.string}: $atkBase  ${Stats.DEFENCE.displayName.string}: $defBase").withStyle(ChatFormatting.LIGHT_PURPLE))
                lines.add(Component.literal("${Stats.SPECIAL_ATTACK.displayName.string}: $spatkBase  ${Stats.SPECIAL_DEFENCE.displayName.string}: $spdefBase  ${Stats.SPEED.displayName.string}: $speedBase").withStyle(ChatFormatting.LIGHT_PURPLE))
            }
        } else {
            lines.add(Component.literal("Bad egg"))
        }

        val timer = stack.getOrDefault(TIMER, DEFAULT_TIMER)
        lines.add(Component.literal(ticksToTime(timer)))
    }

    override fun inventoryTick(stack: ItemStack, world: Level, entity: Entity, slot: Int, selected: Boolean) {
        super.inventoryTick(stack, world, entity, slot, selected)

        if (entity is Player) {
            // Handling a timer to play this action every second instead of every tick
            val second = stack.getOrDefault(SECOND, DEFAULT_SECOND)
            stack.set(SECOND, second + 1)
            if (second < 20) return
            stack.set(SECOND, 0)

            val timer = stack.getOrDefault(TIMER, DEFAULT_TIMER)
            stack.set(TIMER, timer - 20)

            // Egg hatches faster is the player has a pokemon with an ability increasing hatching speed
            if (world.isClientSide && CobbreedingClient.isIncubator)
                stack.set(TIMER, timer - 40)
            else
                if (Cobbreeding.INCUBATOR_ABILITIES_REGISTRY.shouldHatchFaster(entity.stringUUID))
                    stack.set(TIMER, timer - 40)

            if (timer <= 0 && !world.isClientSide) {
                val pokemonProperties = stack.get(EGG_INFO)?.let { PokemonProperties.parse(it) }
                val species = pokemonProperties?.species

                if (species != null && (PokemonSpecies.getByName(species) != null || species == "random")) {
                    if (species == "random") {
                        val randomPokemon = EggUtilities.randomEgg()
                        pokemonProperties.species = randomPokemon.species.showdownId()
                        pokemonProperties.form = randomPokemon.formOnlyShowdownId()
                    }

                    resolveForm(pokemonProperties)
                    hatchEgg(entity, pokemonProperties)
                } else {
                    entity.sendSystemMessage(Component.literal("Couldn't resolve pokemon species to hatch, deleting egg."))
                }
                stack.shrink(1)
            }
        }
    }

    private fun resolveForm(properties: PokemonProperties) {
        if (properties.form != null) {
            properties!!.species?.let { PokemonSpecies.getByName(it) }!!.forms.find { it.formOnlyShowdownId() == properties.form }?.run {
                aspects.forEach {
                    // alternative form
                    properties.customProperties.add(FlagSpeciesFeature(it, true))
                    // regional bias
                    properties.customProperties.add(
                        StringSpeciesFeature(
                            "region_bias",
                            it.split("-").last()
                        )
                    )
                    // Basculin wants to be special
                    // We're handling aspects now but some form handling should be kept to prevent
                    // legitimate abilities to be flagged as forced
                    properties.customProperties.add(
                        StringSpeciesFeature(
                            "fish_stripes",
                            it.removeSuffix("striped")
                        )
                    )
                }
            }
        }
    }

    private fun hatchEgg(entity: Player, properties: PokemonProperties) {
        try {
            CobblemonEvents.HATCH_EGG_PRE.post(HatchEggEvent.Pre(properties, entity as ServerPlayer))
            val pokemon = properties.create()
            pokemon.setFriendship(120)
            pokemon.forcedAspects = pokemonPropertiesToAspects(properties.originalString)

            // Adds the hatched pokémon to the party/pc and registers it in the pokedex
            Cobblemon.storage.getParty(entity.uuid, entity.registryAccess()).add(pokemon)
            Cobblemon.playerDataManager.getPokedexData(entity.uuid).catch(pokemon)

            CobblemonEvents.HATCH_EGG_POST.post(HatchEggEvent.Post(properties, entity))
        } catch (e: Exception) {
            Cobbreeding.LOGGER.error("Egg hatching failed: ${e.message}\n${e.stackTrace}")
            entity.sendSystemMessage(Component.translatable("cobbreeding.msg.egg_hatch.fail"))
        }
    }

    /**
     * Convert ticks to minutes and seconds
     * @return string representing time.
     */
    private fun ticksToTime(ticks: Int): String {
        val minutes = floor((ticks / 1200).toFloat()).toInt()
        val seconds = "%02d".format(floor((ticks % 1200 / 20).toFloat()).toInt())


        return if (minutes <= 0)
            seconds
        else
            "$minutes:$seconds"
    }

    /**
     * Finds aspects in the Pokemon Properties and converts them to a set.
     */
    private fun pokemonPropertiesToAspects(originalString: String): Set<String> {
        if (originalString.contains("aspects=")) {
            val aspects = originalString.split(" ").find { it.contains("aspects") }!!.split("=")[1]
                .removePrefix("[").removeSuffix("]").replace(" ", "")

            return aspects.split(",").toSet()
        }

        return setOf()
    }
}
